const bcrypt = require('bcrypt');
let Sequelize = require('sequelize');
let Op = Sequelize.Op;
let User = require('../models/User');
let Role = require('../models/Role');
let Department = require('../models/Department');
let pwd = require('../../config/lib/pwd');

let attributes = [
    'id',
    'name',
    // [Sequelize.col('role.name'), 'role_name'],
    'permission',
    'status',
    'ip',
    'updated_at',
    'created_at'
];

class UserService {
    static async encryPwd({name, part_id}) {
        let password = await pwd();
        let newUser = { name, part_id, password };
        return new Promise((resolve, reject) => {
            bcrypt.genSalt($config._sr, (err, salt) => { //密码强度，回调函数
                bcrypt.hash(newUser.password, salt, async (err, hash) => { //需要加密项，回调函数
                    if (err) resolve(err.stack);
                    newUser.password = hash; //保存加密结果
                    resolve(await {user: this.createUser(newUser), password});
                })
            })
        })
    }
    static async createUser(param) {
        try {
            return await User.create(param)
        } catch (e) {
            return e.stack
        }
    }
    static async findUserByName({ name }) {
        try {
            return await User.findOne({attributes, where: { name }})
        } catch (e) {
            return e.stack;
        }
    }
    static async register(param){
        let user = await this.findUserByName(param);

        if(typeof user === 'string') return user;
        if(user) {
            return 'Error: 用户名已存在，请重新输入';
        }else{
            return await this.encryPwd(param);
        }
    }
    static async recordIP(client, id, proxyType = 'nginx') {
        /**
         * 过滤伪造IP
         * server {
         *      listen 80;
         *      server_name www.xxx.com xxx.com;
         *      location / {
         *          proxy_pass http://127.0.0.1:8080;
         *          proxy_set_header x-real-ip $remote_addr;
         *          proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
         *          proxy_set_header host $http_host;
         *      }
         * }
         * 参考文档：
         * http://www.nginx.cn/doc/standard/httpproxy.html
         * https://www.jianshu.com/p/22e53bcd3be9
         */
        try {
            let ip = client.connection.remoteAddress || client.socket.remoteAddress || (client.connection.socket ? client.connection.socket.remoteAddress : null);
            console.log(ip);
            
            // 如果使用了nginx代理
            // headers上的信息容易被伪造,但是我不care,自有办法过滤,例如'x-nginx-proxy'和'x-real-ip'我在nginx配置里做了一层拦截把他们设置成了'true'和真实ip,所以不用担心被伪造
            // 如果没用代理的话,我直接通过client.connection.remoteAddress获取到的也是真实ip,所以我不care
            if (proxyType === 'nginx') ip = client.headers['x-real-ip'] || client.headers['x-forwarded-for'] || ip;

            const ipArr = ip.split(',');
            // 如果使用了nginx代理,如果没配置'x-real-ip'只配置了'x-forwarded-for'为$proxy_add_x_forwarded_for,如果客户端也设置了'x-forwarded-for'进行伪造ip
            // 则client.headers['x-forwarded-for']的格式为ip1,ip2只有最后一个才是真实的ip
            if (proxyType === 'nginx') ip = ipArr[ipArr.length - 1];
            if (ip.indexOf('::ffff:') !== -1) ip = ip.substring(7);
            return await User.update({ ip }, {where: { id }});
        } catch (e) {
            return e.stack;
        }
    }

    static async getUserList(param) {
        let page_num = Number(param.page_num) || 1,
            limit = Number(param.page_size) || 10;
        let offset = page_num == 1 ? 0 : limit * ( page_num - 1 );
        let where = {};
        let d_where = {};
        if(param.name) where.name = { [Op.like]: `%${param.name}%` };
        if(param.part_id) d_where = { id: param.part_id };
        let include = [
            {
                model: Role
            },
            {
                model: Department,
                where: d_where
            }
        ];
        let order = [['updated_at', 'desc']];
        try {
            let result = await User.findAndCountAll({ attributes, where, offset, limit, include, order });
            
            return {
                total: result.count,
                list: result.rows,
                page_num,
                page_size: limit
            }
        } catch (e) {
            return e.stack;
        }
    }
    static async changeUserStatus({ id }, status) {
        try {
            return await User.update({ status }, {where: { id }});
        } catch (e) {
            return e.stack
        }
    }
    static async deleteUser({ id }) {
        try {
            return await User.destroy({where: { id }});
        } catch (e) {
            return e.stack
        }
    }
}

module.exports = UserService;
